/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.qframe.quickc;

import com.sun.tools.javac.code.Symbol.ClassSymbol;
import freemarker.cache.URLTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import org.qframe.quickc.annotations.QHandler;

/**
 *
 * @author gprasad
 */
public class QHandlerAnnotationProcessor implements IAnnotationProcessor {

    public static final String HANDLER_REGESTER_CLASS_GENERATED = "org.qframe.client.generated.HandlerRegisteration";
    public static final String HANDLER_REG_TEMPLATE = "org/qframe/quickc/templates/HandlerRegisteration.java.qc";
    public static final String QHANDLER_INTERFACE = "org.qframe.client.quicklet.IQHandler";
    Configuration conf = new Configuration();
    Template tmp;
    List<QuickletBean> quickletBeans = new ArrayList<QuickletBean>();
    int round = 0;

    public QHandlerAnnotationProcessor() {
        System.out.println(" QHandlerAnnotationProcessor initing.. " + HANDLER_REG_TEMPLATE);
        conf.setTemplateLoader(new URLTemplateLoader() {

            @Override
            protected URL getURL(String name) {
                return QHandlerAnnotationProcessor.class.getClassLoader().getResource(name);
            }
        });
        try {
            System.out.println(" QHandlerAnnotationProcessor.class.getResource(name) : "
                    + QHandlerAnnotationProcessor.class.getClassLoader().getResourceAsStream(HANDLER_REG_TEMPLATE));
            tmp = conf.getTemplate(HANDLER_REG_TEMPLATE);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) throws IOException, TemplateException {
        round++;
        if (round != 1 || alreadyGenerated(processingEnv)) {
            return true;
        }

        Set<? extends Element> annotationElements = roundEnv.getElementsAnnotatedWith(QHandler.class);
        System.out.println(round + " = Processing " + annotationElements + " \n for annotation " + QHandler.class);


        for (Element element : annotationElements) {
            if (!(element instanceof ClassSymbol)) {
                System.out.println(" element : " + element + " is not a class skipping . It of class :" + element.getClass() + "; and of kind :" + element.getKind());
                continue;
            }

            TypeElement typeElement = (TypeElement) element;

            String quilifiedName = typeElement.getQualifiedName().toString();
            String simpleName = typeElement.getSimpleName().toString();
            // If issues chnage this to something around : processingEnv.getTypeUtils().isAssignable(null, null)
            if (!Util.doesTypeInheritInterface(typeElement, QHANDLER_INTERFACE)) {
                throw new QuickletCompilationError(quilifiedName + " does not implement " + QHANDLER_INTERFACE);
            }

            String id = element.getAnnotation(QHandler.class).id();
            String path = element.getAnnotation(QHandler.class).path();
            QuickletBean ql = new QuickletBean(id, simpleName, quilifiedName, path);
            quickletBeans.add(ql);
        }


        Writer writer = processingEnv.getFiler().createSourceFile(HANDLER_REGESTER_CLASS_GENERATED).openWriter();
        HashMap map = new HashMap();
        map.put("quickletList", quickletBeans);
        map.put("dateOfCreation", new Date().toString());

        Writer consoleWriter = new OutputStreamWriter(System.out);
        tmp.process(map, consoleWriter);
        tmp.process(map, writer);
        writer.close();

        return true;
    }

    private boolean alreadyGenerated(ProcessingEnvironment processingEnv) {
        TypeElement generatedElement = processingEnv.getElementUtils().getTypeElement(HANDLER_REGESTER_CLASS_GENERATED);
        System.out.println(HANDLER_REGESTER_CLASS_GENERATED + " generatedElement  exists ? : " + generatedElement);
        if (generatedElement != null) {
            System.out.println(HANDLER_REGESTER_CLASS_GENERATED + " already exists. Will skip generation. Do a clean-build if you want to regenerate.");
            return true;
        }
        return false;
    }

    public static class QuickletBean {

        private String id;
        private String className;
        private String fullClassName;
        private String path;

        public QuickletBean(String id, String className, String fullClassName, String path) {
            this.id = id;
            this.className = className;
            this.fullClassName = fullClassName;
            this.path = path;
        }

        public String getClassName() {
            return className;
        }

        public String getFullClassName() {
            return fullClassName;
        }

        public String getId() {
            return id;
        }

        public String getPath() {
            return path;
        }
    }
}
